/**
 * 通用图片上传表单
 */
import { LoadingOutlined, PlusOutlined } from '@ant-design/icons';
import { useDeepCompareEffect } from 'ahooks';
import { message, Space, Upload } from 'antd';
import type { UploadFile, UploadProps } from 'antd/es/upload/interface';
import type { FC, ReactNode } from 'react';
import { useState } from 'react';
import { history, useModel } from 'umi';
import { v4 as uuidv4 } from 'uuid';

import CommonImgCrop from '@/components/CommonImgCrop';
import { BASE_URL, LOGIN_PATH } from '@/constants/global.const';
import localStorageService from '@/utils/localStorageService';
import StorageManager from '@/utils/StorageManager';

import styles from './index.less';

/**
 * 上传组件
 * - btnText: 上传按钮文字
 * - maxNum: 最大上传数量
 * - width: 限定图片宽度
 * - height: 限定图片高度
 * - maxWidth: 图片最大宽度
 * - maxHeight: 图片最大高度
 * - maxSize: 图片最大尺寸
 * - accept: 支持的图片/文件类型
 * - folder: 上传到服务器文件夹
 * - disabled: 是否禁用
 * - showPreviewIcon: 是否展示预览
 * - needCrop: 是否开启图片裁剪功能
 * - listType: 上传列表的样式
 */
type TProps = {
  extraParams?: Record<string, any>;
  value?: string | string[];
  btnText?: string;
  showBtnText?: boolean;
  maxNum?: number;
  extraInfo?: ReactNode | false;
  onChange?: any;
  maxWidth?: number;
  maxHeight?: number;
  width?: number;
  height?: number;
  maxSize?: number;
  folder?: string;
  listType?: 'text' | 'picture' | 'picture-card';
  accept?: ('.jpg' | '.png' | '.gif' | '.json')[];
  disabled?: boolean;
  showMaxInfo?: boolean;
  showPreviewIcon?: boolean;
  needCrop?: boolean;
};

const MIME_TYPE = {
  ['.jpg']: 'image/jpeg',
  ['.png']: 'image/png',
  ['.gif']: 'image/gif',
};

const CommonUpload: FC<TProps> = (props) => {
  const {
    value = '',
    onChange,
    btnText = '上传图片',
    showBtnText = true,
    maxNum = 1,
    extraParams,
    extraInfo,
    maxSize = 2048,
    width,
    height,
    maxWidth,
    maxHeight,
    folder,
    listType = 'picture-card',
    accept = ['.jpg', '.png'],
    disabled = false,
    showMaxInfo = false,
    showPreviewIcon = false,
    needCrop = true,
  } = props;
  const [loading, setLoading] = useState<boolean>(false);
  const { initialState } = useModel('@@initialState');
  const { imgPrefix = '' } = initialState || {};
  const [fileList, setFileList] = useState<UploadFile[]>([]);
  const retAccept = [...new Set(accept || [])];
  const acceptMime = retAccept.map((o) => MIME_TYPE[o] || '');

  const triggerChange = (changedValue: { url?: string | string[] }) => {
    const { url } = changedValue;
    onChange && onChange?.(url);
  };

  // 上传图片尺寸限制
  const checkImageWH = (file: File) =>
    // 参数分别是上传的file，想要限制的宽，想要限制的高
    new Promise((resolve, reject) => {
      const filereader = new FileReader();
      filereader.onload = (e) => {
        const src = e?.target?.result;
        const image = new Image();
        image.onload = () => {
          if (
            (maxWidth && image.width > maxWidth) ||
            (maxHeight && image.height > maxHeight) ||
            (width && image.width !== width) ||
            (height && image.height !== height)
          ) {
            // 上传图片的宽高与传递过来的限制宽高作比较，超过限制则调用失败回调
            resolve(false);
          } else {
            resolve(true);
          }
        };
        image.onerror = reject;
        image.src = src as string;
      };
      filereader.readAsDataURL(file);
    });

  const beforeUpload = async (file: File) => {
    const token = StorageManager.getCookie('token');
    if (!token) {
      localStorageService.clear();
      history.replace({
        pathname: LOGIN_PATH,
      });
      message.error('登录失效，请重新登录');
      return false;
    }

    const isAcceptType = acceptMime.includes(file.type);
    if (!isAcceptType) {
      message.error('图片或文件格式错误');
      /* message.error(
        `只能上传 ${accept
          .map((o) => o.slice(1))
          .join('/')
          .toUpperCase()} 文件!`,
      ); */
      return false;
    }

    const isOverSize = file.size / 1024 < (file.type === 'image/gif' ? 20 * 1024 : maxSize);
    if (!isOverSize) {
      message.error('文件过大');
      // message.error(`图片大小必须小于${maxSize}kb!`);
      return false;
    }

    if (maxWidth || maxHeight || width || height) {
      const sizeCorrent = await checkImageWH(file);
      if (!sizeCorrent) {
        message.error(`图片宽高不符合要求!`);
        return false;
      }
    }

    return true;
  };

  const beforeUploadCrop = (file: File) => {
    const isOverSize = file.size / 1024 < maxSize;

    if (!isOverSize) {
      message.error('文件过大');
      // message.error(`图片大小必须小于${maxSize}kb!`);
      return false;
    }
    return true;
  };

  const onFileChange: UploadProps['onChange'] = ({ file, fileList: newFileList }) => {
    const { status, response } = file || {};
    setFileList(newFileList);

    // 没有status，说明没有上传，是本地文件
    if (!status) {
      setFileList([...fileList]);
    }
    if (status === 'uploading') {
      setLoading(true);
    }
    if (status === 'done') {
      const { code, data, message: msg } = response || {};
      const avaliableItem = newFileList.filter(
        (obj) => obj?.response?.code === 0 || (obj as any)?.isOut,
      );
      setFileList(avaliableItem);
      if (code === 0) {
        if (maxNum <= 1) {
          triggerChange({ url: data.url });
        } else {
          triggerChange({
            url: avaliableItem.map((obj: any) =>
              obj?.isOut ? obj.originUrl : obj?.response?.data?.url,
            ),
          });
        }
      } else {
        message.error(msg);
      }
      setLoading(false);
    }
    if (status === 'error') {
      setLoading(false);
      setFileList([...fileList]);
      message.error('上传失败');
    }
    // 删除图片
    if (status === 'removed') {
      setLoading(false);
      if (maxNum <= 1) {
        triggerChange({ url: '' });
      } else {
        const avaliableItem = newFileList.filter(
          (obj: any) => obj?.response?.code === 0 || obj?.isOut,
        );
        triggerChange({
          url: avaliableItem.map((obj: any) =>
            obj?.isOut ? obj.originUrl : obj?.response?.data?.url,
          ),
        });
      }
    }
  };

  useDeepCompareEffect(() => {
    if (value) {
      let retFileList: string[] = [];
      if (maxNum <= 1 && typeof value === 'string') {
        retFileList = [value];
      } else if (maxNum > 1 && Array.isArray(value)) {
        retFileList = [...value];
      }
      const list = retFileList.map((obj: string) => ({
        uid: uuidv4(),
        name: 'image',
        status: 'done',
        isOut: true,
        originUrl: obj,
        url: `${imgPrefix}${obj}`,
      }));
      setFileList(list as any);
    } else {
      setFileList([]);
    }
  }, [value]);

  const uploadButton = (
    <div>
      {loading ? <LoadingOutlined /> : <PlusOutlined />}
      {showBtnText ? <div style={{ marginTop: 8 }}>{btnText}</div> : null}
    </div>
  );

  return (
    <div className={styles.uploadWrap}>
      {showMaxInfo ? (
        <div
          className={styles.desc}
        >{`最多上传${maxNum}张图片（${fileList.length}/${maxNum}）`}</div>
      ) : null}
      {needCrop ? (
        <CommonImgCrop width={width} height={height}>
          <Upload
            className={disabled ? 'custom-upload disabled' : 'custom-upload'}
            name="file"
            accept={retAccept.join(',')}
            listType={listType || 'picture-card'}
            headers={{
              ticket: `${StorageManager.getCookie('token')}`,
              contentType: 'multipart/form-data',
            }}
            data={{
              folder: folder || 'test',
              ...extraParams,
            }}
            showUploadList={{
              showPreviewIcon,
            }}
            fileList={fileList}
            action={`${BASE_URL}/common/upload`}
            disabled={disabled}
            beforeUpload={beforeUploadCrop}
            onChange={onFileChange}
          >
            {fileList.length < maxNum && uploadButton}
          </Upload>
        </CommonImgCrop>
      ) : (
        <Upload
          className={disabled ? 'custom-upload disabled' : 'custom-upload'}
          name="file"
          accept={retAccept.join(',')}
          listType={listType || 'picture-card'}
          headers={{
            ticket: `${StorageManager.getCookie('token')}`,
            contentType: 'multipart/form-data',
          }}
          data={{
            folder: folder || 'test',
            ...extraParams,
          }}
          showUploadList={{
            showPreviewIcon,
          }}
          fileList={fileList}
          action={`${BASE_URL}/common/upload`}
          disabled={disabled}
          beforeUpload={beforeUpload}
          onChange={onFileChange}
        >
          {fileList.length < maxNum && uploadButton}
        </Upload>
      )}
      {extraInfo ? (
        extraInfo
      ) : extraInfo === false ? null : (
        <Space
          className="space-no-gap"
          direction="vertical"
          align="center"
          style={{ color: '#aaaaaa' }}
        >
          <span>图片支持.jpg,.png</span>
          <span>尺寸120x120px</span>
          <span>{`大小<500KB`}</span>
        </Space>
      )}
    </div>
  );
};

export default CommonUpload;
